package org.ying.container.aop;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

public class CglibMethodInterceptor implements MethodInterceptor {
    private Object target;
    private AspectInfo[] aspectInfos;

    public CglibMethodInterceptor(Object target, AspectInfo[] aspectInfos) {
        this.target = target;
        this.aspectInfos = aspectInfos;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        for (AspectInfo aspectInfo : aspectInfos){
            Class<? extends Annotation> annotation = aspectInfo.getPointCut().annotation();
            if (method.isAnnotationPresent(annotation)){
                Aspect.Result result = aspectInfo.getAspect().before(target, method, objects);
                if (!result.getToNext()){
                    return result.getObject();
                }
            }
        }
        Object obj = null;
        try {
            obj = method.invoke(target, objects);
            //obj = ReflectUtil.invoke(target, method, objects);
            //obj = methodProxy.invokeSuper(o, objects);
        } catch (Throwable throwable) {
            if (throwable.getCause() instanceof InvocationTargetException) {
                for (AspectInfo aspectInfo : aspectInfos){
                    Class<? extends Annotation> annotation = aspectInfo.getPointCut().annotation();
                    if (method.isAnnotationPresent(annotation)){
                        Aspect.Result result = aspectInfo.getAspect().afterException(target, method, objects,throwable);
                        if (!result.getToNext()){
                            return result.getObject();
                        }
                    }
                }
            } else {
                throw throwable;// 其它异常属于代理的异常，直接抛出
            }
        }
        for (int i = aspectInfos.length -1; i >= 0; i--) {
            Class<? extends Annotation> annotation = aspectInfos[i].getPointCut().annotation();
            if (method.isAnnotationPresent(annotation)){
                Aspect.Result result = aspectInfos[i].getAspect().after(target, method, objects);
                if (!result.getToNext()){
                    return result.getObject();
                }
            }
        }
        return obj;
    }
}
